﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using PasteTimer.usermodels;
using Microsoft.Extensions.Options;

namespace PasteTimer
{
    /// <summary>
    /// 这里的权限筛选器
    /// </summary>
    public class RoleAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// 权限
        /// </summary>
        private string _role { set; get; }

        /// <summary>
        /// 角色
        /// </summary>
        private string _model { get; set; }


        private readonly IAppCache _appCache;

        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="appcache"></param>
        /// <param name="serviceProvider"></param>
        /// <param name="Model"></param>
        /// <param name="Role"></param>
        public RoleAttribute(
            IAppCache appcache,
            IServiceProvider serviceProvider,
            string Model = default,
            string Role = default
            )
        {
            _serviceProvider = serviceProvider;
            _role = Role;
            _model = Model;
            //_redisClient = redisClient;
            _appCache = appcache;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <exception cref="Volo.Abp.UserFriendlyException"></exception>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //Console.WriteLine($"{DateTime.Now} model:{_model} role:{_role}");


            if (!context.HttpContext.Request.Headers.ContainsKey("token"))
            {
                throw new Volo.Abp.UserFriendlyException("当前未登录，请登录后重试", "401");
            }


            //base.cursued.id = 5;

            //下面判断有问题
            //时间戳
            var token = context.HttpContext.Request.Headers["token"].ToString();
            token = token.Replace("Bearer ", "");

            //var infostr = "";// _redisClient.GetStringValue(token);
            if (!String.IsNullOrEmpty(token))
            {

                var gridcode = Task.Run<string>(() =>
                {
                    return _appCache.ReadStringAsync(token);
                }).Result;

                if (!String.IsNullOrEmpty(gridcode))
                {
                    if (!string.IsNullOrEmpty(_model))
                    {
                        var roles = Task.Run(() =>
                        {
                            return _appCache.ReadObject<List<RoleInfoDto>>("role:list:" + gridcode);
                        }).Result;

                        if (roles == null || roles == default)
                        {
                            using var _dbContext = _serviceProvider.GetRequiredService<IPasteTimerDbContext>();
                            //从数据库读取
                            var listquery = from gradeinfo in _dbContext.GradeInfo.Where(x => x.Name == gridcode)
                                            join b in _dbContext.GradeRole.Where(x => 1 == 1) on gradeinfo.Id equals b.GradeId into abc
                                            from graderole in abc.DefaultIfEmpty()
                                            join ctab in _dbContext.RoleInfo.Where(x => 1 == 1) on graderole.RoleId equals ctab.Id into bbc
                                            from roleinfo in bbc.DefaultIfEmpty()
                                            select new RoleInfoDto
                                            {
                                                Model = roleinfo.Model,
                                                Name = roleinfo.Name,
                                                Id = roleinfo.Id
                                            };
                            roles = listquery.ToList();
                            if (roles != null && roles.Count > 0)
                            {
                                _appCache.SetObject<List<RoleInfoDto>>("role:list:" + gridcode, roles, 3600);
                            }
                            _dbContext.Dispose();
                        }

                        if (roles == null || roles.Count == 0)
                        {
                            throw new Volo.Abp.UserFriendlyException("对应角色不包含权限，请绑定权限后重试", "401");
                        }

                        var findroot = roles.Where(x => x.Name == "root" && x.Model == "root").FirstOrDefault();
                        if (findroot == null || findroot == default)
                        {
                            var hit = roles.Where(x => x.Model == _model && x.Name == _role).FirstOrDefault();
                            if (hit == null || hit == default)
                            {
                                throw new Volo.Abp.UserFriendlyException("当前未登录，请登录后重试", "403");
                            }
                        }
                    }
                }
                else
                {
                    throw new Volo.Abp.UserFriendlyException("当前未登录，请登录后重试", "401");
                }

            }
            else
            {
                throw new Volo.Abp.UserFriendlyException("当前密钥信息有误，请登录后重试", "401");
            }
            base.OnActionExecuting(context);
        }
    }

    /// <summary>
    /// XToken的校验
    /// </summary>
    public class XTokenAttribute : ActionFilterAttribute
    {
        private readonly SlaveHelper _slaveHelper;
        private readonly ModelHelper _modelHelper;
        public XTokenAttribute(SlaveHelper slaveHelper, ModelHelper modelHelper)
        {
            _slaveHelper = slaveHelper;
            _modelHelper = modelHelper;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        /// <exception cref="PasteTimerException"></exception>
        public override Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            var _auth_xtoken = false;
            if (context.HttpContext.Request.Headers.ContainsKey("xtoken"))
            {
                var xtoken = context.HttpContext.Request.Headers["xtoken"].ToString();
                var strs = xtoken.Split('_');//time_fromid_toid_fromtoken_totoken
                int.TryParse(strs[1], out var fromslaveid);
                int.TryParse(strs[2], out var toslaveid);
                if (toslaveid != 0)
                {
                    if (toslaveid == _slaveHelper.MySlaveId)
                    {
                        //校验token
                        if (fromslaveid != 0)
                        {
                            var fromdto = _modelHelper.SlaveInfoDtoItem(fromslaveid).Result;
                            if (fromdto != null)
                            {
                                var temptoken = $"{strs[0]}_{strs[1]}_{strs[2]}_{fromdto.Token}_{_slaveHelper.MySlaveToken}".ToMd5Lower();
                                if (temptoken == strs[3])
                                {
                                    _auth_xtoken = true;
                                }
                            }
                        }
                    }
                }
            }
            if(!_auth_xtoken)
            {
                throw new PasteTimerException("当前未登录，请登录后重试", "401");
            }
            return base.OnResultExecutionAsync(context, next);
        }
    }

    /// <summary>
    /// Model的校验
    /// </summary>
    public class RunModelAttribute : ActionFilterAttribute
    {
        private readonly TaskConfig _config;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="config"></param>
        public RunModelAttribute(IOptions<TaskConfig> config)
        {
            _config = config.Value;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <exception cref="PasteTimerException"></exception>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (_config.SingleModel)
            {
                throw new PasteTimerException("System Config is Single Model Not Slave Model,Http Request Error!");
            }
            else
            {
                if (context.HttpContext.Request.Headers.ContainsKey("stoken"))
                {
                    if (context.HttpContext.Request.Headers["stoken"].ToString() != _config.PublicToken)
                    {
                        throw new PasteTimerException("Header stoken Error!",401);
                    }
                }
                else
                {
                    throw new PasteTimerException("Header stoken Not Found, Error!",401);
                }
            }
            base.OnActionExecuting(context);
        }

    }


    /// <summary>
    /// 
    /// </summary>
    public class ErrorInfoModel
    {
        /// <summary>
        /// 
        /// </summary>
        public string code { get; set; } = "500";

        /// <summary>
        /// 
        /// </summary>
        public bool success { get; set; } = false;

        /// <summary>
        /// 
        /// </summary>
        public string message { get; set; } = "";
    }

    /// <summary>
    /// 自定义全局错误处理，使用错误代码httpstatuscode
    /// </summary>
    public class TaskExceptionAttribute : ExceptionFilterAttribute
    {

        /// <summary>
        /// 
        /// </summary>
        private readonly ILogger<TaskExceptionAttribute> _logger;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logger"></param>
        public TaskExceptionAttribute(ILogger<TaskExceptionAttribute> logger)
        {
            _logger = logger;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public override void OnException(ExceptionContext context)
        {

            // 如果异常没有被处理则进行处理
            if (context.ExceptionHandled == false)
            {
                var _userexception = context.Exception as Volo.Abp.UserFriendlyException;

                var info = new ErrorInfoModel();
                info.code = "500";
                info.success = false;
                info.message = "服务器遇到一个错误，无法继续为您服务!";

                if (_userexception != null)
                {
                    if (!String.IsNullOrEmpty(_userexception.Code))
                    {
                        info.code = _userexception.Code;
                    }
                    else
                    {
                        info.code = "502";
                    }
                    info.message = context.Exception.Message;
                }
                else
                {

                    var volexception = context.Exception as PasteTimerException;
                    if (volexception != null)
                    {
                        info.code = $"{volexception.Code}";
                        info.message = volexception.Message;
                    }
                    else
                    {
                        var _exception = context.Exception as Exception;
                        if (_exception != null)
                        {
                            info.code = "500";
                            info.message = _exception.Message;
                        }
                    }
                }

                if (context.ModelState != null)
                {
                    if (context.ModelState.Count > 0)
                    {
                        foreach (var key in context.ModelState.Keys)
                        {
                            context.ModelState.TryGetValue(key, out var val);
                            if (val.Errors.Count > 0)
                            {
                                info.message = key + "::" + val.Errors[0].ErrorMessage;
                                info.code = "400";
                                break;
                            }
                        }
                    }
                }

                //400的错误信息

                if (info.code == "500")
                {
                    _logger.LogError(context.Exception, context.HttpContext.Request.Path, null);
                }

                context.Result = new ContentResult
                {
                    // 返回状态码设置为200，表示成功
                    StatusCode = int.Parse(info.code),
                    // 设置返回格式
                    ContentType = "application/json;charset=utf-8",
                    Content = Newtonsoft.Json.JsonConvert.SerializeObject(info)
                };
            }
            // 设置为true，表示异常已经被处理了
            context.ExceptionHandled = true;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override System.Threading.Tasks.Task OnExceptionAsync(ExceptionContext context)
        {
            return base.OnExceptionAsync(context);
        }
    }

}
